home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / rpc / rpcOutput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  11.7 KB  |  365 lines

  1. /*
  2.  * rpcOutput.c --
  3.  *
  4.  *    The output routine for the RPC system.  Large packets are
  5.  *    fragmented upon ouput here.
  6.  *
  7.  * Copyright 1986 Regents of the University of California
  8.  * All rights reserved.
  9.  */
  10.  
  11. #ifndef lint
  12. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/rpc/rpcOutput.c,v 9.8 92/12/13 18:21:34 mgbaker Exp $ SPRITE (Berkeley)";
  13. #endif /* not lint */
  14.  
  15.  
  16. #include <sprite.h>
  17. #include <mach.h>
  18. #include <rpc.h>
  19. #include <rpcInt.h>
  20. #include <rpcTrace.h>
  21. #include <net.h>
  22. #include <proc.h>
  23. #include <sync.h>
  24. #include <status.h>
  25. #include <dbg.h>
  26. #include <fsio.h>
  27. #include <fsrecov.h>
  28. #include <stdio.h>
  29. #include <recov.h>
  30.  
  31. /*
  32.  * A delay variable that represents our preferred inter-fragment delay.
  33.  * This is told to other machines by including it in the RPC header.
  34.  * They use it to set the delay between packets in a fragmented send.
  35.  */
  36. unsigned    short rpcMyDelay;
  37. unsigned    short rpcOutputRate;
  38. short    rpcDelay[NET_NUM_SPRITE_HOSTS];
  39.  
  40. short rpcLastDelay;
  41.  
  42. #ifdef PRINT_PACKETS
  43. Boolean rpcDumpPackets = FALSE;
  44. #endif /* PRINT_PACKETS */
  45.  
  46.  
  47. /*
  48.  *----------------------------------------------------------------------
  49.  *
  50.  * RpcOutput --
  51.  *
  52.  *      Send a message to the host specified by spriteID.  Packets over a
  53.  *      certain size are fragmented by this routine into several datagrams
  54.  *      and reassembled by the dispatch routine of the receiver.  Our
  55.  *      caller has to pass in an array of buffer specifications that this
  56.  *      routine uses if it has to fragment the message.  The RPC header
  57.  *      and the dontSendMask are also used in conjuction with fragmented
  58.  *      packets.
  59.  *      Master Lock note: This routine may busy wait for a few hundred
  60.  *      microseconds in between sending successive packets of a large
  61.  *      message.  This delay is defeated if there is a Master Lock held.
  62.  *      *mutexPtr, if non-NIL, is released during this delay, and then
  63.  *      reaquired.  (This is done because the DMA ethernet driver needs an
  64.  *      interrupt serviced after each packet output.  Things work without
  65.  *      enabling interrupts, but the packets get queued for output until
  66.  *      after the caller of RpcOutput releases the MasterLock.  This
  67.  *      causes one big delay between the 1rst and 2nd packet, and no delay
  68.  *      between ones after that.)
  69.  *
  70.  * Results:
  71.  *    SUCCESS on non-fragmented sends, or an error code related
  72.  *    to fragmenting.
  73.  *
  74.  * Side effects:
  75.  *    Call the ethernet output routine and trace.
  76.  *
  77.  *----------------------------------------------------------------------
  78.  */
  79. ReturnStatus
  80. RpcOutput(spriteID, rpcHdrPtr, message, fragment, dontSendMask, mutexPtr)
  81.     int            spriteID;    /* Destination host */
  82.     register RpcHdr    *rpcHdrPtr;    /* The RPC header. */
  83.     RpcBufferSet    *message;    /* A set of 4 scatter/gather vector
  84.                      * elements that specify where the proto
  85.                      * header, RPC header, parameters, 
  86.                      * and data are. */
  87.     RpcBufferSet    *fragment;    /* An array of buffer sets used if
  88.                      * the message needs to be
  89.                      * fragmented.  This needs to be
  90.                      * previously set up so that the
  91.                      * first buffer references valid
  92.                      * storage for an RPC header. */
  93.     unsigned int    dontSendMask;    /* For fragmenting.  Bits set in this
  94.                      * mask suppress sending of the
  95.                      * corresponding fragment.  A good
  96.                      * value for this is returned in
  97.                      * partial acknowlegment messages */
  98.     Sync_Semaphore    *mutexPtr;    /* This mutex is released while we
  99.                      * output the message.  If NIL, no
  100.                      * mutex is released.  This is done
  101.                      * in honor of DMA interfaces that
  102.                      * interrupt after they output a packet.
  103.                      */
  104. {
  105.     Net_Route        *routePtr;
  106.     ReturnStatus    status;
  107. #ifdef PRINT_PACKETS
  108.     if (rpcDumpPackets) {
  109.     register unsigned short *shortPtr;
  110.     register int i;
  111.  
  112.     printf("RpcOutput - Raw packet at %x:\n", rpcHdrPtr);
  113.     shortPtr = (unsigned short *)rpcHdrPtr;
  114.     for (i=0 ; i<sizeof(RpcHdr)/2 ; i++) {
  115.         printf("%x ", *shortPtr);
  116.         shortPtr++;
  117.         if (((i+1)%8) == 0) {
  118.         printf("\n");
  119.         }
  120.     }
  121.     printf("\n");
  122.  
  123.     printf("RpcOutput - buffer set:\n");
  124.     printf("%x %x\n", message->rpcHdrBuffer.bufAddr,
  125.                message->rpcHdrBuffer.length);
  126.     printf("%x %x\n", message->paramBuffer.bufAddr,
  127.                message->paramBuffer.length);
  128.     printf("%x %x\n", message->dataBuffer.bufAddr,
  129.                message->dataBuffer.length);
  130.     }
  131. #endif /* PRINT_PACKETS */
  132.     /*
  133.      * Mark our packets if we aren't up all the way.  This means that the
  134.      * other host won't pay attention to our packets in terms of recovery.
  135.      */
  136.     if (!rpcServiceEnabled) {
  137.     rpcHdrPtr->flags |= RPC_NOT_ACTIVE;
  138.     }
  139.     /* We're doing transparent server recovery. */
  140.     if (recov_Transparent && fsrecov_AlreadyInit) {
  141.     rpcHdrPtr->flags |= RPC_FAST;
  142.     }
  143.     if (recov_ServerDriven) {
  144.     rpcHdrPtr->flags |= RPC_SERVER_RECOV;
  145.     }
  146.     /* 
  147.      * Find a route to the host. 
  148.      */
  149.     routePtr = Net_IDToRoute(spriteID, -1, TRUE, mutexPtr, 
  150.             rpcHdrPtr->paramSize + rpcHdrPtr->dataSize);
  151.     if (routePtr == (Net_Route *) NIL) {
  152.     return RPC_INTERNAL_ERROR;
  153.     }
  154.     /*
  155.      * Check to see if we have to fragment.   Note that we pack the first
  156.      * fragment as full as possible so that it might contain more than
  157.      * 1K of data.  If we fragment, however, we break things on 1K boundaries.
  158.      */
  159.     if (rpcHdrPtr->paramSize + rpcHdrPtr->dataSize >
  160.     routePtr->maxPacket - sizeof(RpcHdr)) {
  161.     if (rpcHdrPtr->paramSize > RPC_MAX_PARAMSIZE) {
  162.         return(RPC_PARAMS_TOOBIG);
  163.     } else if (rpcHdrPtr->dataSize > RPC_MAX_DATASIZE) {
  164.         return(RPC_DATA_TOOBIG);
  165.     } else {
  166.         /*
  167.          * Send a fragmented message.
  168.          */
  169.         register int dataSize, paramSize;    /* Size remaining in data and
  170.                          * parameter areas that needs
  171.                          * to go in subsequent frags. */
  172.         int dataOffset, paramOffset;    /* Offset of fragment data */
  173.         int frag;                /* Fragment index */
  174.         int nfrags;                /* Total number of fragments */
  175.         int delay;                /* Inter-fragment delay */
  176.         register int fragID;        /* Bitmask ID of fragment.  The
  177.                          * I'th bit of this is set on
  178.                          * the I'th fragment. */
  179.         register int sendFragMask;        /* Complement of the dont-send
  180.                          * mask. */
  181.         register RpcHdr *fragRpcHdrPtr;    /* RPC header of a fragment */
  182.  
  183.         dataSize = rpcHdrPtr->dataSize;
  184.         paramSize = rpcHdrPtr->paramSize;
  185.  
  186.         /*
  187.          * Loop one time to compute and record the sizes of the
  188.          * parameter and data areas of each fragment.
  189.          */
  190.         nfrags = 0;
  191.         dataOffset = 0;
  192.         paramOffset = 0;
  193.         while (dataSize > 0 || paramSize > 0) {
  194.         register int dlen, plen;
  195.  
  196.         /*
  197.          * Fill the fragments with the parameter area followed by
  198.          * the data area.  The max size ethernet packet is used
  199.          * for best throughput.
  200.          */
  201.         if (paramSize) {
  202.             plen = (routePtr->maxPacket - sizeof(RpcHdr));
  203.             plen = (plen > paramSize ? paramSize : plen);
  204.             paramSize -= plen;
  205.         } else {
  206.             plen = 0;
  207.         }
  208.         if (dataSize) {
  209.             dlen = (routePtr->maxPacket - sizeof(RpcHdr) - plen);
  210.             dlen = (dlen > dataSize ? dataSize : dlen);
  211.             dataSize -= dlen;
  212.         } else {
  213.             dlen = 0;
  214.         }
  215.         fragRpcHdrPtr = (RpcHdr *)fragment[nfrags].rpcHdrBuffer.bufAddr;
  216.  
  217.         fragRpcHdrPtr->paramSize = plen;
  218.         fragRpcHdrPtr->dataSize = dlen;
  219.         fragRpcHdrPtr->paramOffset = paramOffset;
  220.         fragRpcHdrPtr->dataOffset = dataOffset;
  221.  
  222.         fragment[nfrags].paramBuffer.length = plen;
  223.         fragment[nfrags].paramBuffer.bufAddr =
  224.             message->paramBuffer.bufAddr + paramOffset;
  225.  
  226.         fragment[nfrags].dataBuffer.length = dlen;
  227.         fragment[nfrags].dataBuffer.bufAddr =
  228.             message->dataBuffer.bufAddr + dataOffset;
  229.  
  230.         dataOffset += dlen;
  231.         paramOffset += plen;
  232.         nfrags++;
  233.         }
  234.  
  235.         /*
  236.          * An inter-fragment delay is setup when going to a slower machine.
  237.          */
  238.         if (rpcDelay[spriteID] > rpcOutputRate) {
  239.         delay = rpcDelay[spriteID] - rpcOutputRate;
  240.         } else {
  241.         delay = 0;
  242.         }
  243.         /*
  244.          * Loop (again) to output the fragments.  Fragments are not output
  245.          * if their bit is set in the dontSendMask.  If dontSentMask
  246.          * would suppress all fragments, i.e. this is a keep-alive resend,
  247.          * we just send the last fragment.  Also, if this is a resend
  248.          * by the client and we haven't recieved a partial acknowledgment
  249.          * from the server we only resend the last fragment as a probe.
  250.          * This is for the case of large writes where the initial
  251.          * timeout period is too short.  We don't want to resend the
  252.          * whole packet unless we have to.
  253.          */
  254.         if ((dontSendMask == rpcCompleteMask[nfrags]) ||
  255.         ((rpcHdrPtr->flags & RPC_PLSACK) && (dontSendMask == 0))) {
  256.         sendFragMask = (1 << (nfrags - 1));
  257.         } else {
  258.         sendFragMask = ~dontSendMask;
  259.         }
  260.         for (fragID = 1, frag = 0;
  261.          frag < nfrags;
  262.          fragID <<= 1, frag++) {
  263.         if (fragID & sendFragMask) {
  264.  
  265.             fragRpcHdrPtr =
  266.                 (RpcHdr *)fragment[frag].rpcHdrBuffer.bufAddr;
  267.  
  268.             sendFragMask &= ~fragID;
  269.             /*
  270.              * Mark the last fragment of the batch so the receiver
  271.              * can check for a complete message.
  272.              */
  273.             if (sendFragMask == 0) {
  274.             fragRpcHdrPtr->flags |= RPC_LASTFRAG;
  275.             }
  276.             fragRpcHdrPtr->version =    rpc_NativeVersion;
  277.             fragRpcHdrPtr->flags =    rpcHdrPtr->flags;
  278.             fragRpcHdrPtr->clientID =    rpcHdrPtr->clientID;
  279.             fragRpcHdrPtr->serverID =    rpcHdrPtr->serverID;
  280.             fragRpcHdrPtr->channel =    rpcHdrPtr->channel;
  281.             fragRpcHdrPtr->serverHint =    rpcHdrPtr->serverHint;
  282.             fragRpcHdrPtr->bootID =    rpcHdrPtr->bootID;
  283.             fragRpcHdrPtr->ID =        rpcHdrPtr->ID;
  284.             fragRpcHdrPtr->delay =    rpcMyDelay;
  285.             fragRpcHdrPtr->numFrags =    nfrags;
  286.             fragRpcHdrPtr->fragMask =    fragID;
  287.             fragRpcHdrPtr->command =    rpcHdrPtr->command;
  288.  
  289.             /*
  290.              * The network routines expect an array of scatter/gather
  291.              * elements.  The RpcBufferSet is a struct of 4 of
  292.              * these so we cast its address into a (Net_ScatterGather *)
  293.              *
  294.              * Note that we only pass our mutex to Net on the last
  295.              * fragment.  With a mutex the packet transmission is
  296.              * synchronous, the Net_Output call doesn't return until
  297.              * the packet has been transmitted.  We only want this
  298.              * on the last fragment to prevent the obscure case where
  299.              * otherwise we might time out and retransmit before
  300.              * the packet is even on the wire.
  301.              */
  302.             status = Net_Output(spriteID,
  303.                 (Net_ScatterGather *)&fragment[frag], 4,
  304.                 ((fragRpcHdrPtr->flags & RPC_LASTFRAG) ?
  305.                  mutexPtr : (Sync_Semaphore *)NIL ),
  306.                  routePtr);
  307.             if (status != SUCCESS) {
  308.             return status;
  309.             }
  310.             /*
  311.              * Insert a delay after all but the last fragment.
  312.              * The master lock is released here to enable
  313.              * interrupts.  The ethernet driver needs an interrupt
  314.              * serviced in between the output of each packet.
  315.              */
  316.             RPC_TRACE(fragRpcHdrPtr, RPC_OUTPUT, "Fragout");
  317.             if (mutexPtr != (Sync_Semaphore *)NIL) {
  318.             if (Mach_AtInterruptLevel()) {
  319.                 panic(
  320.                   "RpcOutput, unlocking mutex at interrupt level");
  321.             } else {
  322.                 MASTER_UNLOCK(mutexPtr);
  323.             }
  324.             }
  325.             rpcLastDelay = delay;
  326.             if (delay &&
  327.             ((fragRpcHdrPtr->flags & RPC_LASTFRAG) == 0)) {
  328.             MACH_DELAY(delay);
  329.             }
  330.             if (mutexPtr != (Sync_Semaphore *)NIL) {
  331.             MASTER_LOCK(mutexPtr);
  332.             }
  333.         }
  334.         }
  335.     }
  336.     } else {
  337.     /*
  338.      * No fragmenting.
  339.      */
  340.     rpcHdrPtr->numFrags = 0;
  341.     rpcHdrPtr->paramOffset = 0;
  342.     rpcHdrPtr->dataOffset = 0;
  343.     rpcHdrPtr->version = rpc_NativeVersion;
  344.     message->rpcHdrBuffer.length = sizeof(RpcHdr);
  345.     if ((rpcHdrPtr->flags & RPC_TYPE) == RPC_ACK) {
  346.         /*
  347.          * Don't disturb the fragment mask.
  348.          */
  349.     } else {
  350.         rpcHdrPtr->fragMask = 0;
  351.     }
  352. #ifdef TIMESTAMP
  353.     RPC_NIL_TRACE(RPC_ETHER_OUT, "Ether output");
  354. #endif /* TIMESTAMP */
  355.     status = Net_Output(spriteID, (Net_ScatterGather *)message, 4, mutexPtr,
  356.         routePtr);
  357.     if (status != SUCCESS) {
  358.         return status;
  359.     }
  360.     RPC_TRACE(rpcHdrPtr, RPC_OUTPUT, "Output");
  361.     }
  362.     Net_ReleaseRoute(routePtr);
  363.     return(SUCCESS);
  364. }
  365.